home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <stdlib.h>
- #include <dos.h>
- #include <ctype.h>
- #include <dir.h>
- #include <mem.h>
-
- #include "dosstruc.h"
-
- #define MAX12BIT 0x0FF6
- #if defined(__TINY__)
- #define MODEL "Tiny"
- #endif
- #if defined(__SMALL__)
- #define MODEL "Small"
- #endif
- #if defined(__MEDIUM__)
- #define MODEL "Medium"
- #endif
- #if defined(__COMPACT__)
- #define MODEL "Compact"
- #endif
- #if defined(__LARGE__)
- #define MODEL "Large"
- #endif
- #if defined(__HUGE__)
- #define MODEL "Huge"
- #endif
-
- struct DpbStruct Dpb; /* Disk Parameter Blcok (see dosstruc.h) */
- struct ClusterQueue CluQ; /* Queue of cluster for directory */
- struct DirEntry *DirBuff; /* Buffer for directory to be sorted */
- unsigned LastCluster; /* Value for end of cluster chain */
- int Is12Bit; /* 12 / 16 bit cluster indicator */
- int *CluArray; /* Cluster Array ptr, dynamically allocated */
- char Disk; /* Alpha working disk ('A', 'B', .... ) */
- char CurDir[67]; /* Storage for Current Directory of disk */
- char Path[67]; /* Storage for Path to sort */
- char Parent[67]; /* Storage for Parent part of Path */
- char Element[13]; /* Storage for Child part of Path */
- char *Fat; /* Pointer to FAT buffer (dynamic) */
- char Line[80]; /* Working storage for strings */
- unsigned Cluster, Sector, NumSec;
- unsigned MinMem; /* Minimum available memory */
- struct ExtendedEntry Dir;
- int Lim, i, j, k, l;
- struct ClusterEntry *p, *t;
- int OutSectors, OutClusters, BytesPerCluster, ECount;
- struct ExtFcb Fcb;
- char Order = 'N'; /* Sort key indicator (Default=Name/Ext) */
- char Inverse = 0; /* Ascend/Descend indic. (Default=Ascend) */
- char Level = 0; /* Recursive sort indic. (default=Recursic) */
- char RSwt = 0; /* Report switch (Default=No Report) */
- char VerSwt = 0; /* Pause for operator verify (Default=off) */
- char Packed = 1; /* Elim. "erased" entries (Default=on) */
-
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- char *strrspn();
- void SortDir(), ShowRoot(), Usage();
-
- char *p;
- union REGS Reg;
- unsigned Cluster, Sector;
- int i, j, AbortProgram();
-
- fputs("C-Sort And Pack [CSAP]: Version 2.08b: Date: 07-30-1987", stderr);
- fputs(" [", stderr);
- fputs(MODEL, stderr);
- fputs(" Model]\n", stderr);
-
- fputs(" use \"CSAP -H\" or \"CSAP ?\" for help.\n\n", stderr);
- Disk = getdisk() + 'A';
- Line[0] = '\\'; getcurdir(Disk - '@', &Line[1]);
-
- ctrlbrk(AbortProgram); /* Install "wrap-up" in Control Break vec. */
-
- /* Interpret command line arguments, if any */
-
- for (i=1; i<argc; ++i) {
- if (argv[i][0] == '-') {
- for (j=1; j<strlen(argv[i]); ++j) {
- switch (toupper(argv[i][j])) {
- case 'N': /* Sort Key = Name/Ext (default) */
- Order = 'N';
- break;
- case 'D': /* Sort Key = Date/Time */
- Order = 'D';
- break;
- case 'E': /* Sort Key = Ext/Name */
- Order = 'E';
- break;
- case 'S': /* Sort Key = File Size */
- Order = 'S';
- break;
- case 'R': /* Report Dir loc. & "erased" */
- RSwt = 1;
- break;
- case 'I': /* Sort order inverse */
- Inverse = 1;
- break;
- case 'P': /* Do NOT remove "erased" entries */
- Packed = 0;
- break;
- case 'L': /* Limit sort to one level */
- Level = 1;
- break;
- case 'V': /* Request approval before sort */
- VerSwt = 1;
- break;
- case 'H':
- Usage();
- default: /* Illegal option */
- fprintf(stderr, "Invalid option %s.\n", argv[i]);
- Usage();
- break;
- }
- }
- }
- else { /* Not switch, assume directory name or '?' */
- if (argv[i][0] == '?') Usage();
- if (argv[i][1] == ':') { /* Check for disk specified */
- Disk = toupper(argv[i][0]); p = &argv[i][2];
- }
- else p = &argv[i][0];
- if (p[0] != '\\') {
- Line[0] = '\\'; getcurdir(Disk - '@', &Line[1]);
- strcat(Line, "\\"); strcat(Line, p);
- }
- else strcpy(Line,p);
- }
- }
-
- /*
- Get disk information - uses un-documented DOS call, Int 21H, Func. 32H
- This function has been verified to work correctly in PC/MS-DOS
- versions 2.0 through 3.3. It is heavily used by DOS programs such
- as CHKDSK.
- */
-
- GetDPB(Disk, &Dpb);
-
- /* Establish whether disk has 16-bit or 12-bit clusters */
-
- Is12Bit = (Dpb.LastCluster > MAX12BIT) ? 0 : 1;
- LastCluster = (Is12Bit) ? 0x0FF8 : 0xFFF8;
-
- /*
- Get & save current directory of working disk. We have to change to sort
- and must restore on termination
- */
- CurDir[0] = Disk; CurDir[1] = ':'; CurDir[2] = '\\';
- getcurdir(Disk - '@', (char *) &CurDir[3]);
-
- /* Allocate space to hold entire FAT in memory and read it in */
-
- if ((Fat = malloc(Dpb.FatSize * Dpb.SectorSize)) == NULL) {
- fprintf(stderr, "Insufficient memory for FAT.\n");
- exit(1);
- }
- if (absread(Disk-'A', Dpb.FatSize, Dpb.FatStart, Fat) != 0) {
- fprintf(stderr, "Error reading FAT.\n");
- exit(1);
- }
-
- /*
- Develop full path name for directory to be sorted and separate into
- Parent and Child portions
- */
-
- Path[0] = Parent[0] = Element[0] = '\0';
- Path[0] = Disk; Path[1] = ':';
- Path[2] = 0x00;
- if (Line[0] != '\\') {
- strcat(Path, "\\"); strcpy(&Path[3], &CurDir[3]);
- if ((Path[strlen(Path)-1] != '\\') && (Path[strlen(Path)-1] != '/'))
- strcat(Path, "\\");
- }
- strcat(Path, Line);
- p = strrspn(Path, "\\/");
- strcpy(Element, &p[1]);
- if (p[-1] == ':') p++;
- strncpy(Parent, Path, p - Path); Parent[p - Path] = 0x00;
-
- MinMem = coreleft(); /* Initialize minimum available memory */
-
- /*
- Perform sort. SortDir is recursive and, if Level is not on, will sort
- sort all levels of the hierarchy from the starting level down
- */
-
- SortDir();
-
- printf("Minimum memory= %u\n", MinMem);
-
- bdos(0x3B, (int) CurDir, 0); /* Restore input "current" directory */
- } /* end Main */
-
-
- /*
- STRRSPN is simply a reverse version of STRSPN. It finds the LAST
- occurance in S1 of any member of S2. Fo some reason, none of the C
- compilers that I use provide this although they all provide STRSPN
- */
-
- char *strrspn (s1, s2)
- char *s1, *s2;
- {
- char *p2start = s2;
- char *p1;
-
- p1 = s1 + strlen(s1) - 1;
- while (p1 >= s1) {
- while (*s2) {
- if (*p1 == *s2) return(p1);
- s2++;
- }
- s2 = p2start;
- p1--;
- }
- return( (char *) NULL);
- }
-
-
- /* SearchFirst -- Search for First Directory Entry.
- * On entry fcb contains an extended File Control Block
- * with file name and attribute bits set. On exit, fcb
- * contains matched entry unless return code is 255, in
- * which case no match was found. This routine is used
- * instead of the ones provided by the caller so that the
- * cluster information for the directory can be obtained.
- */
- SearchFirst(Fcb)
- struct ExtFcb *Fcb;
- {
- union REGS regs;
-
- regs.x.ax = 0x1100;
- regs.x.dx = (unsigned) Fcb;
- intdos(®s, ®s);
- return((int) (regs.x.ax & 0xFF));
- }
-
- /* Alu2Sec -- Converts an input cluster number [ALU] into the disk-relative
- * sector for use with DOS Absolute Disk Read [interrupt 25H] or
- * Absolute Disk Write [interrupt 26H]. Requires access to the
- * undocumented DOS Disk Parameter Block [use funtion GetDPB].
- */
- unsigned int Alu2Sec (Dpb, Alu)
- struct DpbStruct *Dpb;
- unsigned Alu;
- {
- return( (Alu - 2) * (Dpb->ClusterSize + 1) + Dpb->DataStart);
- }
-
- /* NextCl -- This function calculates the logical "chaining" of cluster
- * numbers in a File Allocation Table [FAT]. Given an entry
- * cluster number it calculates the next cluster using the
- * array Fat[].
- *
- * If Is12Bit is TRUE then Fat[] is assumed to contain 12 bit
- * entries, otherwise Fat[] is assumed to contain 16 bit entries.
- */
- unsigned NextCl(Is12Bit, Cluster, Fat)
- int Is12Bit;
- unsigned Cluster;
- unsigned char Fat[];
- {
- unsigned ClWord, ClOffset;
-
- if (Is12Bit) { /* 12 bit FAT lookup */
- ClOffset = 3 * Cluster / 2;
- ClWord = Fat[ClOffset] + (Fat[ClOffset + 1] << 8);
- if (Cluster & 1) return (ClWord >> 4); /* odd cluster */
- else return (ClWord & 0x0FFF); /* even cluster */
- }
- else return (((unsigned int *) Fat)[Cluster]); /* 16 bit FAT lookup */
- }
-
-
- /* PutQueue -- Builds a simple FIFO linked list using dynamically acquired
- * memory.
- */
- void PutQueue (Q, Cluster)
- struct ClusterQueue *Q;
- unsigned Cluster;
- {
- struct ClusterEntry *p;
-
- if ((p = malloc(sizeof(struct ClusterEntry))) == NULL) {
- fprintf(stderr, "Insufficient memory(1).\n");
- AbortProgram();
- }
- p->Next = NULL; p->Cluster = Cluster;
- if (Q->Head == NULL) Q->Head = p;
- else Q->Current->Next = p;
- Q->Current = p; Q->Count++;
- }
-
- /* AbortProgram -- Aborts the program, resetting the current directory,
- * with an error code of 1.
- */
- int AbortProgram () {
-
- bdos(0x3B, (int) CurDir, 0); /* Reset input Current Directory */
- exit(1);
- }
-
-
-
- /* strincmp -- The comparsion routine for the qsort algorithm.
- */
- int strincmp (a, b)
- struct DirEntry *a, *b;
- {
- int i;
- long t;
-
- /* Ensure that "erased" entries sort high no matter what the sort key is. */
-
- if ((a->Name[0] == 0xE5) && (b->Name[0] != 0xE5)) return(1);
- if (b->Name[0] == 0xE5) return(-1);
-
- /* Ensure that directories sort lower that files no matter what sort key */
-
- if ((a->Name[0] != 0xE5) && (b->Name[0] != 0xE5)) {
- if ((a->Attribute & 0x10) ^ (b->Attribute & 0x10)) {
- if (a->Attribute & 0x10) return(-1);
- else return(1);
- }
- }
-
- /* Actual sort key compare routines */
-
- switch (Order) {
- case 'D': /* Sort key is Date/Time */
- if ((t = a->ModifyDate - b->ModifyDate) == 0) {
- t = a->ModifyTime - b->ModifyTime;
- }
- break;
- case 'N': /* Sort key is Name/Ext (default) */
- t = strncmp(a->Name, b->Name, 11);
- break;
- case 'E': /* Sort key is Ext/Name */
- if ((t = strncmp(a->Ext, b->Ext, 3)) == 0) {
- t = strncmp(a->Name, b->Name, 8);
- }
- break;
- case 'S': /* Sort key is File Size */
- t = a->FileSize - b->FileSize;
- break;
- default:
- t = strncmp(a->Name, b->Name, 11);
- break;
- }
- if (Inverse) t = -t; /* Sort order is inverse */
- return((t < 0) ? -1 : ((t > 0) ? 1 : 0));
- }
-
- void Usage () {
-
- printf("USAGE: CSAP [options] [[d:]directory_name]\n");
- printf(" or\n");
- printf(" CSAP [[d:]directory_name] [options]\n");
- printf("\n");
- printf("Options:\n");
- printf(" -N Sort on Name/Ext (default).\n");
- printf(" -D Sort on Date/Time.\n");
- printf(" -E Sort on Ext/Name.\n");
- printf(" -S Sort on File Size.\n");
- printf("\n");
- printf(" -R Report number of \"erased\" entries and directory location.\n");
- printf(" -I Inverse sort order, i.e. descending.\n");
- printf(" -P Do NOT remove \"erased\" entries.\n");
- printf(" -L Limit sort to a single level.\n");
- printf(" -V Request confirmation before sorting.\n");
- printf(" -H This message.\n");
- exit(0);
- }